package kuwo

import (
	"bytes"
	"encoding/json"
	"github.com/cnsilvan/UnblockNeteaseMusic/provider/base"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/cnsilvan/UnblockNeteaseMusic/common"
	"github.com/cnsilvan/UnblockNeteaseMusic/network"
	"github.com/cnsilvan/UnblockNeteaseMusic/utils"
)

const (
	APIGetSongURL = "http://trackercdn.kugou.com/i/v2/?pid=2&behavior=play&cmd=25"
)

type KuGou struct{}

func (m *KuGou) SearchSong(song common.SearchSong) (songs []*common.Song) {
	song = base.PreSearchSong(song)
	cookies := getCookies()
	result, err := base.Fetch(
		"http://songsearch.kugou.com/song_search_v2?keyword="+song.Keyword+"&page=1",
		cookies, nil, true)
	if err != nil {
		log.Println(err)
		return songs
	}
	data := result["data"]
	if data != nil {
		if dMap, ok := data.(common.MapType); ok {
			if lists, ok := dMap["lists"]; ok {
				if listSlice, ok := lists.(common.SliceType); ok {
					listLength := len(listSlice)
					if listLength > 0 {
						maxIndex := listLength/2 + 1
						if maxIndex > 10 {
							maxIndex = 10
						}
						for index, matched := range listSlice {
							if index >= maxIndex {
								break
							}
							if kugouSong, ok := matched.(common.MapType); ok {
								if _, ok := kugouSong["FileHash"].(string); ok {
									songResult := &common.Song{}
									singerName, _ := kugouSong["SingerName"].(string)
									songName, _ := kugouSong["SongName"].(string)
									songResult.PlatformUniqueKey = kugouSong
									songResult.PlatformUniqueKey["UnKeyWord"] = song.Keyword
									songResult.Source = "kugou"
									songResult.Name = songName
									songResult.Artist = singerName
									songResult.Artist = strings.ReplaceAll(singerName, " ", "")
									songResult.AlbumName, _ = kugouSong["AlbumName"].(string)
									songResult.Id, ok = kugouSong["ID"].(string)
									if len(songResult.Id) > 0 {
										songResult.Id = string(common.KuGouTag) + songResult.Id
									}
									songResult.MatchScore, ok = base.CalScore(song, songName, singerName, index, maxIndex)
									if !ok {
										continue
									}
									songs = append(songs, songResult)

								}

							}

						}
					}

				}

			}
		}
	}
	return base.AfterSearchSong(song, songs)
}
func (m *KuGou) GetSongUrl(searchSong common.SearchMusic, song *common.Song) *common.Song {

	if fileHash, ok := song.PlatformUniqueKey["FileHash"].(string); ok && len(fileHash) > 0 {
		clientRequest := network.ClientRequest{
			Method:    http.MethodGet,
			RemoteUrl: APIGetSongURL + "&hash=" + fileHash + "&key=" + utils.MD5([]byte(fileHash+"kgcloudv2")),
			Host:      "trackercdnbj.kugou.com",
			//Cookies:              cookies,
			Header:               nil,
			ForbiddenEncodeQuery: true,
			Proxy:                false,
		}
		resp, err := network.Request(&clientRequest)
		if err != nil {
			log.Println(err)
			return song
		}
		defer resp.Body.Close()
		body, err := network.StealResponseBody(resp)
		songData := utils.ParseJsonV2(body)
		status, ok := songData["status"].(json.Number)
		if !ok || status.String() != "1" {
			log.Println(song.PlatformUniqueKey["UnKeyWord"].(string) + "，该歌曲酷狗版权保护")
			log.Println(utils.ToJson(songData))
			return song
		}
		songUrls, ok := songData["url"].(common.SliceType)
		if ok && len(songUrls) > 0 {
			songUrl, ok := songUrls[0].(string)
			if ok && strings.Index(songUrl, "http") == 0 {
				song.Url = songUrl
				if br, ok := songData["bitRate"]; ok {
					switch br.(type) {
					case json.Number:
						song.Br, _ = strconv.Atoi(br.(json.Number).String())
					case int:
						song.Br = br.(int)
					}
				}
				return song

			}
		}
	}
	return song
}

func (m *KuGou) ParseSong(searchSong common.SearchSong) *common.Song {
	song := &common.Song{}
	songs := m.SearchSong(searchSong)
	if len(songs) > 0 {
		song = m.GetSongUrl(common.SearchMusic{Quality: searchSong.Quality}, songs[0])
	}
	return song
}

func getCookies() []*http.Cookie {
	cookies := make([]*http.Cookie, 1)
	cookie := &http.Cookie{Name: "kg_mid", Value: createGuid(), Path: "kugou.com", Domain: "kugou.com"}
	cookies[0] = cookie
	return cookies
}
func createGuid() string {
	guid := s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4()
	return utils.MD5(bytes.NewBufferString(guid).Bytes())
}
func s4() string {
	num := uint64((1 + common.Rand.Float64()) * 0x10000)
	num = num | 0
	return strconv.FormatUint(num, 16)[1:]
}
